package com.bestcem.xm.ticket.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.ticket.dao.RspdTimerDao;
import com.bestcem.xm.ticket.dao.TicketDao;
import com.bestcem.xm.ticket.dao.TicketRuleDao;
import com.bestcem.xm.ticket.entity.mongo.RspdTimer;
import com.bestcem.xm.ticket.entity.mongo.Ticket;
import com.bestcem.xm.ticket.entity.mongo.TicketRule;
import com.bestcem.xm.ticket.enums.RspdTimerStatusEnum;
import com.bestcem.xm.ticket.enums.TicketConditionCategoryEnum;
import com.bestcem.xm.ticket.enums.TicketOperationTypeEnum;
import com.bestcem.xm.ticket.grpc.client.TicketBaseDeliverGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketDeliverGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketSurveyGrpcService;
import com.bestcem.xm.ticket.grpc.client.dto.deliver.DeliverAgainTaskDTO;
import com.bestcem.xm.ticket.grpc.client.dto.survey.RespondentDTO;
import com.bestcem.xm.ticket.service.DeliverAgainService;
import com.bestcem.xm.ticket.service.dto.mq.DeliverAgainDTO;
import com.bestcem.xm.ticket.service.dto.ticket.rule.FilterEntityDTO;
import com.bestcem.xm.ticket.service.dto.ticket.rule.ValueEntityDTO;
import com.bestcem.xm.ticket.util.DeliverAgainCheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * DS_TICKET_DAO 从工单迁移过来的record表
 *
 * @author jy.zhao
 * @version 1.0
 * @date 2021/8/19 17:07
 **/
@Service
@Slf4j
public class DeliverAgainServiceImpl implements DeliverAgainService {

    @Resource
    private TicketRuleDao ticketRuleDao;

    @Resource
    private DeliverAgainCheckUtil deliverAgainCheckUtil;

    @Resource
    private TicketDao ticketDao;

    @Resource
    private RspdTimerDao rspdTimerDao;

    @Resource
    private TicketSurveyGrpcService ticketSurveyGrpcService;

    @Resource
    private TicketDeliverGrpcService ticketDeliverGrpcService;

    @Resource
    private TicketBaseDeliverGrpcService ticketBaseDeliverGrpcService;

    @Override
    public void validDeliverAgainCondition(DeliverAgainDTO deliverAgainDTO) {
        if (log.isInfoEnabled()) {
            log.info("[ticket] deliverAgain触发。 start");
            log.info("[ticket] deliverAgain触发。data={}", deliverAgainDTO);
        }
        if (!validDeliverAgainDTO(deliverAgainDTO)) {
            return;
        }
        // 1. 取出传递的工单规则id数组和二次投放记录id
        List<String> ruleIdList = deliverAgainDTO.getRuleIdList();
        String againDeliverRecordId = deliverAgainDTO.getAgainDeliverRecordId();
        // 2. 把工单按照是否是时间触发分类
        List<String> existRuleIdList = new ArrayList<>();
        List<Long> timeTriggerList = new ArrayList<>();
        // 3. 分类结果。existRuleIdList存在的规则id。timeTriggerList时间触发的规则id
        for (String ruleId : ruleIdList) {
            TicketRule ticketRule = ticketRuleDao.findById(ruleId);
            if (Validator.isNull(ticketRule) || Validator.isNull(ticketRule.getCondition()) || CollUtil.isEmpty(ticketRule.getCondition().getFilters())) {
                continue;
            }
            // 3.1 存在的规则id
            existRuleIdList.add(ruleId);
            // 规则是否需要更新
            boolean needUpdate = false;
            List<JSONObject> filterJsonList = ticketRule.getCondition().getFilters();
            if (CollectionUtils.isEmpty(filterJsonList)) {
                continue;
            }
            List<FilterEntityDTO> filters = new ArrayList<>();
            for (JSONObject jsonObject : filterJsonList) {
                filters.add(JSON.toJavaObject(jsonObject, FilterEntityDTO.class));
            }
            for (FilterEntityDTO filter : filters) {
                ValueEntityDTO valueEntityDTO = JSON.toJavaObject(filter.getValue(), ValueEntityDTO.class);
                if (Validator.isNull(filter.getCategory()) || filter.getCategory() != TicketConditionCategoryEnum.RESPONDENT_STATUS_CHANGE.getIndex() ||
                        Validator.isNull(valueEntityDTO.getDays())) {
                    continue;
                }
                // 预计触发时间， 单位为秒
                LocalDateTime triggerTime = DateUtil.getCurrentTime().plusDays(valueEntityDTO.getDays());
                long expireSecond = DateUtil.toSecond(triggerTime);
                valueEntityDTO.setExpire(expireSecond);
                // 3.2 规则id预计触发时间
                timeTriggerList.add(expireSecond);
                needUpdate = true;
                filter.setValue((JSONObject) JSON.toJSON(valueEntityDTO));
            }
            if (needUpdate) {
                List<JSONObject> newFilterJsonList = new ArrayList<>();
                for (FilterEntityDTO filter : filters) {
                    newFilterJsonList.add((JSONObject) JSON.toJSON(filter));
                }
                TicketRule.Condition condition = ticketRule.getCondition();
                condition.setFilters(newFilterJsonList);
                boolean successFlg = ticketRuleDao.updateTicketRuleCondition(ticketRule.getId(), condition);
                if (!successFlg) {
                    log.error("[ticket] 工单规则更新失败");
                    break;
                }
            }
        }
        // 4. 规则id预计时间不为空，找到最小的触发时间，保存rspdTimer记录,用于定时任务改变工单状态
        Long minTriggerSecond = timeTriggerList.stream().min(Comparator.naturalOrder()).orElse(-1L);
        if (minTriggerSecond > -1) {
            // 保存rspdTimer记录,用于定时任务改变工单状态
            RspdTimer rspdTimer = new RspdTimer();
            rspdTimer.setSearch(new RspdTimer.Search(againDeliverRecordId));
            rspdTimer.setExpire(minTriggerSecond.intValue());
            rspdTimer.setRuleIdList(existRuleIdList);
            rspdTimer.setStatus(RspdTimerStatusEnum.UNHANDLE.getIndex());
            rspdTimerDao.saveRespondentTimer(rspdTimer);
            if (log.isInfoEnabled()) {
                log.info("[ticket] 保存二次投放任务相关，rspdTimer={}", rspdTimer);
            }
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] deliverAgain触发。结束");
        }
    }

    /**
     * 校验二次投放参数
     *
     * @param deliverAgainDTO 二次投放参数
     * @return boolean
     * @author jy.zhao
     * @date 2021/8/25 13:13
     **/
    private boolean validDeliverAgainDTO(DeliverAgainDTO deliverAgainDTO) {
        List<String> ruleIdList = deliverAgainDTO.getRuleIdList();
        if (CollUtil.isEmpty(ruleIdList)) {
            if (log.isWarnEnabled()) {
                log.warn("[ticket] deliverAgain触发,没有传递规则列表。deliverAgainDTO={}", deliverAgainDTO);
            }
            return false;
        }
        String againDeliverRecordId = deliverAgainDTO.getAgainDeliverRecordId();
        if (Validator.isEmpty(againDeliverRecordId)) {
            if (log.isWarnEnabled()) {
                log.warn("[ticket] deliverAgain触发,没有传递二次投放记录id。deliverAgainDTO={}", deliverAgainDTO);
            }
            return false;
        }
        return true;
    }


    @Override
    public void validTicketAndDeliverAgain(Ticket ticket, Integer scene, LocalDateTime callTime) {
        // 1. 根据工单id查询工单
//        Ticket ticket = ticketDao.findById(ticket);
        if (Validator.isNull(ticket)) {
            log.error("[ticket] 没有找到工单,ticket={}对应的工单", ticket);
            return;
        }
        if (TicketOperationTypeEnum.MANUAL.getIndex().equals(ticket.getOperationType())) {
            log.info("[ticket] 工单为手动创建工单，ticketId= {}", ticket.getId());
            return;
        }
        // 2. 查询二次投放任务列表
        List<DeliverAgainTaskDTO> deliverAgainTaskDTOList = ticketBaseDeliverGrpcService.listAgainDeliverTask(ticket.getOrgId(), ticket.getSurveyId());
        if (CollUtil.isEmpty(deliverAgainTaskDTOList)) {
            if (log.isWarnEnabled()) {
                log.warn("[ticket] 没有查询到二次投放任务");
            }
            return;
        }
        // 3. 检查二次投放任务条件成立的投放任务列表
        deliverAgainTaskDTOList = deliverAgainCheckUtil.checkDeliverAgainCondition(ticket, scene, callTime, deliverAgainTaskDTOList);
        if (deliverAgainTaskDTOList.isEmpty()) {
            if (log.isInfoEnabled()) {
                log.info("[ticket] 没有条件成立的投放任务列表");
            }
            return;
        }
        // 4. 进行二次投放
        againDeliver(ticket, deliverAgainTaskDTOList);
    }

    /**
     * 二次投放，根据组织id，答卷编号进行二次投放
     *
     * @param ticket                  工单
     * @param deliverAgainTaskDTOList 条件成立的二次投放任务
     * @author jy.zhao
     * @date 2021/8/24 15:51
     **/
    private void againDeliver(Ticket ticket, List<DeliverAgainTaskDTO> deliverAgainTaskDTOList) {
//        Ticket ticket = ticketDao.findById(ticketId);
        String deliverId = null;
        String memberId = "";
        // 根据答卷序号获取答卷信息。
        RespondentDTO respondent = ticketSurveyGrpcService.getRespondentBySeq(ticket.getResId(), ticket.getSurveyId());
        if (Validator.isNotNull(respondent)) {
            deliverId = respondent.getDeliverId();
            memberId = respondent.getMemberId();
        }
        // rpc进行二次投放，根据二次投放任务id和deliver_id查找到投放方式，决定是否进行二次投放
        if (Validator.isEmpty(deliverId)) {
            return;
        }
        for (DeliverAgainTaskDTO deliverAgainTaskDTO : deliverAgainTaskDTOList) {
            String recordId = ticketDeliverGrpcService.createTicketAgainDeliver(deliverAgainTaskDTO.getId(), deliverId, ticket.getId(), ticket.getResId(), memberId, ticket.getOrgId(), deliverAgainTaskDTO.getDeliverProjectId());
            if (log.isInfoEnabled()) {
                log.info("[ticket] 生成的二次投放的记录id={}", recordId);
            }
        }
    }
}
